package com.jfree.nettyshow.handler;

import com.alibaba.fastjson.JSON;
import com.jfree.nettyshow.common.CommonConstant;
import com.jfree.nettyshow.common.Result;
import com.jfree.nettyshow.common.SessionManager;
import com.jfree.nettyshow.config.NettyConfiguration;
import com.jfree.nettyshow.entity.BaseBusinessTask;
import com.jfree.nettyshow.entity.Message;
import com.jfree.nettyshow.entity.Session;
import io.netty.channel.*;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.SocketAddress;


@ChannelHandler.Sharable
public class ServerTaskHandler extends SimpleChannelInboundHandler<String> {

    // private ThreadLocal<List<Session>> local = new ThreadLocal();
    private static Logger logger = LoggerFactory.getLogger(ServerTaskHandler.class);

    private AttributeKey<Session> attributeKey = AttributeKey.valueOf(CommonConstant.SESSION_CHANNEL_KEY);

    public ServerTaskHandler(SessionManager sessionManager) {
        super();
        this.sessionManager = sessionManager;
        logger.info("构造方法当前线程：" + Thread.currentThread().getName());

    }

    private SessionManager sessionManager;


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        logger.info("channelRead0当前线程：" + Thread.currentThread().getName());
        if (msg == null) {
            throw new Exception("请求参数为空");
        }
        Message message = JSON.parseObject(msg, Message.class);
        if (!sessionManager.getSession(ctx.channel()).isCheck() && !CommonConstant.ZERO.equals(message.getActionType())) {
            ctx.channel().writeAndFlush(Result.loginErr()).addListener((ChannelFutureListener) future -> System.out.println("addListener threadName====" + Thread.currentThread().getName()));
            logger.info("当前channel没有验证:" + ctx.channel().id().asShortText());
        }
        NettyConfiguration.getPool()
                .submit(new BaseBusinessTask() //todo 这里可以把BaseBusinessTask绑定线程复用
                        .setMessage(message)
                        .setChannel(ctx.channel()));//这里可以优化，让channel没有关联，快速被gc
        ctx.channel().attr(attributeKey).get().setLastAccessTime(System.currentTimeMillis());
        ctx.fireChannelRead(msg);//todo 防止后面还有处理逻辑

    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //todo 不一定是在读取到数据完成触发，也有可能在连接时触发
        logger.info("channelReadComplete当前线程：" + Thread.currentThread().getName());
        ctx.fireChannelReadComplete();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        logger.error("session:" + ctx.channel().attr(attributeKey).toString() + ",异常:cause：" + cause.toString());
        //ctx.channel().close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        logger.info("userEventTriggered当前线程：" + Thread.currentThread().getName());
        Session currentSession = ctx.channel().attr(attributeKey).get(); //这边可能要判断空值
        //可以在注册的时候判断channel isClose isXxx方法要去看下
        //TODO  超时处理
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //todo 检查重复登录
        ctx.channel().config().setWriteBufferHighWaterMark(10 * 1024 * 1024);
        logger.info("channelActive当前线程：" + Thread.currentThread().getName());
        Channel channel = ctx.channel();
        SocketAddress address = channel.remoteAddress();
        logger.debug("create connect:" + address.toString());
        Session session = new Session();
        session.setSessionId(channel.id().asShortText());
        session.setChannel(channel);
        session.setLastAccessTime(System.currentTimeMillis());
        channel.attr(attributeKey).set(session);
        sessionManager.put(session.getSessionId(), session);
        logger.info("连接成功：" + session.toString());
//        List<Session> sessions = local.get();
//        if (sessions == null) {
//            sessions = new ArrayList<>();
//            local.set(sessions);
//        }
//        sessions.add(session);
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info(ctx.channel().remoteAddress().toString() + ":disconnect");
        sessionManager.closeChannel(ctx.channel());
        //super.channelInactive(ctx);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        logger.info("----ctx channelRegistered-----,threadName:{}", Thread.currentThread().getName());
        ctx.fireChannelRegistered();
    }

}
